/*
 * Copyright (C) 2011  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

#ifndef _ejit_private_h
#define _ejit_private_h

#define jit_cc_a0_reg		0x00000001	/* arg0 is a register */
#define jit_cc_a0_chg		0x00000002	/* arg0 is modified */
#define jit_cc_a0_jmp		0x00000004	/* arg0 is a jump target */
#define jit_cc_a0_int		0x00000010	/* arg0 is immediate word */
#define jit_cc_a0_flt		0x00000020	/* arg0 is immediate float */
#define jit_cc_a0_dbl		0x00000040	/* arg0 is immediate double */
#define jit_cc_a1_reg		0x00000100	/* arg1 is a register */
#define jit_cc_a1_chg		0x00000200	/* arg1 is modified */
#define jit_cc_a1_int		0x00001000	/* arg1 is immediate word */
#define jit_cc_a1_flt		0x00002000	/* arg1 is immediate float */
#define jit_cc_a1_dbl		0x00004000	/* arg1 is immediate double */
#define jit_cc_a2_reg		0x00010000	/* arg2 is a register */
#define jit_cc_a2_chg		0x00020000	/* arg2 is modified */
#define jit_cc_a2_int		0x00100000	/* arg2 is immediate word */
#define jit_cc_a2_flt		0x00200000	/* arg2 is immediate float */
#define jit_cc_a2_dbl		0x00400000	/* arg2 is immediate double */

#if JIT_REGSET_MPZ
/* only required to use JIT_REGSET_MPZ if more than 64 registers, and still,
 * may be better to define a new int128 or similar type for register masks */
#  define jit_regset_com(u, v)		mpz_com(u, v)
#  define jit_regset_and(u, v, w)	mpz_and(u, v, w)
#  define jit_regset_ior(u, v, w)	mpz_ior(u, v, w)
#  define jit_regset_xor(u, v, w)	mpz_xor(u, v, w)
#  define jit_regset_set(u, v)		mpz_set(u, v)
#  define jit_regset_cmp_ui(u, v)	mpz_cmp_ui(u, v)
#  define jit_regset_set_ui(u, v)	mpz_set_ui(u, v)
#  define jit_regset_set_p(set)		mpz_sgn(set)
#  define jit_regset_clrbit(set, bit)	mpz_clrbit(set, bit)
#  define jit_regset_setbit(set, bit)	mpz_setbit(set, bit)
#  define jit_regset_tstbit(set, bit)	mpz_tstbit(set, bit)
#  define jit_regset_scan1(set, off)	mpz_scan1(set, off)
#  define jit_regset_new(set)		enew_mpz_u((jit_pointer_t *)&(set), 0)
#elif JIT_REGSET_INT
#  define jit_regset_com(u, v)		((u) = ~(v))
#  define jit_regset_and(u, v, w)	((u) = (v) & (w))
#  define jit_regset_ior(u, v, w)	((u) = (v) | (w))
#  define jit_regset_xor(u, v, w)	((u) = (v) ^ (w))
#  define jit_regset_set(u, v)		((u) = (v))
#  define jit_regset_cmp_ui(u, v)	((u) != (v))
#  define jit_regset_set_ui(u, v)	((u) = (v))
#  define jit_regset_set_p(set)		(set)
#  if DEBUG
#    define jit_regset_clrbit(set, bit)					\
	(assert(bit >= 0 && bit < (sizeof(jit_regset_t) << 3)),		\
	 (set) &= ~(1LL << (bit)))
#    define jit_regset_setbit(set, bit)					\
	(assert(bit >= 0 && bit < (sizeof(jit_regset_t) << 3)),		\
	 (set) |= 1LL << (bit))
#    define jit_regset_tstbit(set, bit)					\
	(assert(bit >= 0 && bit < (sizeof(jit_regset_t) << 3)),		\
	 (set) & (1LL << (bit)))
#  else
#    define jit_regset_clrbit(set, bit)	((set) &= ~(1LL << (bit)))
#    define jit_regset_setbit(set, bit)	((set) |= 1LL << (bit))
#    define jit_regset_tstbit(set, bit)	((set) & (1LL << (bit)))
#  endif
#  define jit_regset_new(set)		((set) = 0)
extern unsigned long
jit_regset_scan1(jit_regset_t, jit_int32_t);
#else
#  error "Define either JIT_REGSET_MPZ or JIT_REGSET_INT"
#endif

#define jit_reglive_setup()						\
    do {								\
	jit_regset_set_ui(_jit->reglive, 0);				\
	jit_regset_set_ui(_jit->regmask, 0);				\
    } while (0)

#define jit_new_node_no_link(c)	_jit_new_node_no_link(_jit,c)
extern jit_node_t *
_jit_new_node_no_link(jit_state_t*, jit_code_t);

#define jit_link_node(n)	_jit_link_node(_jit,n)
extern void
_jit_link_node(jit_state_t *_jit, jit_node_t *node);

#define jit_link_label(l)	_jit_link_label(_jit,l)
extern void
_jit_link_label(jit_state_t*,jit_node_t*);

#define jit_reglive(node)	_jit_reglive(_jit, node)
extern void
_jit_reglive(jit_state_t*, jit_node_t*);

#define jit_regarg_set(n,v)	_jit_regarg_set(_jit,n,v)
extern void
_jit_regarg_set(jit_state_t*, jit_node_t*, jit_int32_t);

#define jit_regarg_clr(n,v)	_jit_regarg_clr(_jit,n,v)
extern void
_jit_regarg_clr(jit_state_t*, jit_node_t*, jit_int32_t);

#define jit_get_reg(s)		_jit_get_reg(_jit,s)
extern jit_int32_t
_jit_get_reg(jit_state_t*, jit_int32_t);

#define jit_unget_reg(r)	_jit_unget_reg(_jit,r)
extern void
_jit_unget_reg(jit_state_t*, jit_int32_t);

#define jit_save(reg)		_jit_save(_jit, reg)
extern void
_jit_save(jit_state_t*, jit_int32_t);

#define jit_load(reg)		_jit_load(_jit, reg)
extern void
_jit_load(jit_state_t*, jit_int32_t);

#define jit_epilog()		_jit_epilog(_jit)
extern void
_jit_epilog(jit_state_t*);

#define jit_optimize()		_jit_optimize(_jit)
extern void
_jit_optimize(jit_state_t*);

#define jit_classify(code)	_jit_classify(_jit, code)
extern jit_int32_t
_jit_classify(jit_state_t*, jit_code_t);

#define jit_regarg_p(n, r)	_jit_regarg_p(_jit, n, r)
extern jit_bool_t
_jit_regarg_p(jit_state_t*, jit_node_t*, jit_int32_t);

#define emit_ldxi(r0, r1, i0)	_emit_ldxi(_jit, r0, r1, i0)
extern void
_emit_ldxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);

#define emit_stxi(i0, r0, r1)	_emit_stxi(_jit, i0, r0, r1)
extern void
_emit_stxi(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);

#define emit_ldxi_d(r0, r1, i0)	_emit_ldxi_d(_jit, r0, r1, i0)
extern void
_emit_ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);

#define emit_stxi_d(i0, r0, r1)	_emit_stxi(_jit, i0, r0, r1)
extern void
_emit_stxi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);

#endif /* _ejit_private_h */
